package org.geekforum.exception;

import lombok.extern.slf4j.Slf4j;
import org.geekforum.common.AppResult;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

/**
 * 🚨 专业的全局异常处理器
 * <p>
 * 提供全面的错误处理，包括:
 * - 结构化的错误响应
 * - 安全感知的错误消息
 * - 详细的调试日志
 * - 用户友好的错误描述
 *
 * @author GeekForum开发团队
 * @version 2.0
 */
@Slf4j
@ControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 🎯 应用特定异常处理器
     */
    @ExceptionHandler(ApplicationException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public AppResult handleApplicationException(ApplicationException e, HttpServletRequest request) {
        log.warn("🔥 应用异常: {} | 路径: {}", e.getMessage(), request.getRequestURI());

        if (e.getErrorResult() != null) {
            return e.getErrorResult();
        }

        String message = (e.getMessage() == null || e.getMessage().trim().isEmpty())
                ? "服务暂时不可用"
                : e.getMessage();

        return AppResult.failed(message);
    }

    /**
     * 🚫 验证异常处理器
     */
    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public AppResult handleValidationException(Exception e) {
        log.warn("📝 验证错误: {}", e.getMessage());
        return AppResult.failed("无效的输入参数。请检查您的数据。");
    }

    /**
     * 🔍 缺少参数处理器
     */
    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public AppResult handleMissingParameter(MissingServletRequestParameterException e) {
        log.warn("❓ 缺少参数: {}", e.getParameterName());
        return AppResult.failed(String.format("缺少必需参数 '%s'", e.getParameterName()));
    }

    /**
     * 🔧 类型不匹配处理器
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public AppResult handleTypeMismatch(MethodArgumentTypeMismatchException e) {
        log.warn("🔄 类型不匹配: {} 对于参数 {}", e.getValue(), e.getName());
        return AppResult.failed(String.format("参数 '%s' 的值 '%s' 无效", e.getName(), e.getValue()));
    }

    /**
     * 🚪 404 未找到处理器
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public AppResult handleNotFound(NoHandlerFoundException e) {
        log.warn("🔍 资源未找到: {} {}", e.getHttpMethod(), e.getRequestURL());
        return AppResult.failed("请求的资源未找到");
    }

    /**
     * 🚨 全局异常处理器（回退）
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public AppResult handleGenericException(Exception e, HttpServletRequest request) {
        // 生成唯一错误编号用于跟踪
        String errorId = String.format("ERR_%d", System.currentTimeMillis());

        // 记录完整的异常详情供调试使用
        log.error("💥 未处理异常 [{}] | 路径: {} | User-Agent: {}",
                errorId, request.getRequestURI(), request.getHeader("User-Agent"), e);

        // 返回通用的用户友好消息（安全考虑）
        Map<String, Object> errorDetails = new HashMap<>();
        errorDetails.put("errorId", errorId);
        errorDetails.put("timestamp", LocalDateTime.now());
        errorDetails.put("path", request.getRequestURI());

        return AppResult.failed("发生意外错误。请稍后再试。");
    }
}

